/***************************************************************************************************
*Copyright(C),2010-2016,Sumscope
*FileName	:  lock.h
*Author	:  scofined.qi
*Version	:  1.0
*Date		:  2015/12/18
*Desc		:  //用于主要说明此程序文件完成的主要功能
*Relation :
*Others	:  //其他内容说明
*Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
*History	:  //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
***************************************************************************************************/
#pragma once

#include "../core.h"
#pragma warning(disable:4251)
#include <mutex>

#ifdef WIN32
#include <windows.h>
#include <atomic>
namespace qb {
	namespace base {

        class S_CORE_EXPORT CSLock {
			CRITICAL_SECTION	m_cs;
		private:
			CSLock(const CSLock& lock) { m_cs = lock.m_cs; }
			CSLock& operator=(const CSLock& lock) { m_cs = lock.m_cs; return *this; }
		public:
			CSLock() { InitializeCriticalSection(&m_cs); }
			explicit CSLock(int spinCount) { InitializeCriticalSectionAndSpinCount(&m_cs, spinCount); }
			~CSLock() { DeleteCriticalSection(&m_cs); }
			void SetSpinCount(int count) { SetCriticalSectionSpinCount(&m_cs, count); }
			void Lock() { EnterCriticalSection(&m_cs); }
			void Unlock() { LeaveCriticalSection(&m_cs); }
		};
        class S_CORE_EXPORT Spinlock {//不可重入
		private:
			typedef enum { Locked, Unlocked } LockState;
			typedef Spinlock LockType;
			std::atomic<LockState> state_;
		public:
			Spinlock() : state_(Unlocked) {}
			void Lock()
			{
				while (state_.exchange(Locked, std::memory_order_acquire) == Locked) {
					/* busy-wait */
				}
			}
			void Unlock()
			{
				state_.store(Unlocked, std::memory_order_release);
			}
		};


		template<class LOCK>
        class ScopedLock {
			LOCK& m_lock;
		private:
			ScopedLock(const ScopedLock& sl) {}
			ScopedLock& operator=(const ScopedLock& sl) { return *this; }
		public:
			ScopedLock(LOCK& lock) :m_lock(lock) { m_lock.Lock(); }
			~ScopedLock() { m_lock.Unlock(); }
		};

		class Mutex {
		public:
			Mutex() {}
			Mutex(const wchar_t* name) {}
			~Mutex() {}

			void Lock() { m_mutex.lock(); }
			bool TryLock() { return m_mutex.try_lock(); }
			void Unlock() { m_mutex.unlock(); }
		private:
			std::recursive_mutex	m_mutex;
		};

		template<class MUTEX>
		class ScopedMutex {
			MUTEX& m_mutex;
		public:
			ScopedMutex(MUTEX& lock) :m_mutex(lock) { m_mutex.Lock(); }
			~ScopedMutex() { m_mutex.Unlock(); }
		};


        class S_CORE_EXPORT Event {
			HANDLE			m_handle;
		public:
			Event(bool manualReset, bool initSignaled, const wchar_t* name = 0);
			bool IsValid() { return m_handle != 0 && m_handle != INVALID_HANDLE_VALUE; }
			void Signal() { ::SetEvent(m_handle); }
			void Reset() { ::ResetEvent(m_handle); }
			DWORD Wait(DWORD timeout) {
				return WaitForSingleObject(m_handle, timeout);
			}

		};
	}//namespace base;
}//namespace qb;

#else
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>

namespace qb {
	namespace base {

		class CSLock {
			pthread_mutex_t	m_cs;
		private:
            CSLock(const CSLock& lock) {
                m_cs = lock.m_cs;
                pthread_mutexattr_t attr;
                pthread_mutexattr_init(&attr);
                pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
                pthread_mutex_init(&m_cs, &attr);
            }
            CSLock& operator=(const CSLock& lock) {
                m_cs = lock.m_cs;
                pthread_mutexattr_t attr;
                pthread_mutexattr_init(&attr);
                pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
                pthread_mutex_init(&m_cs, &attr);
                return *this; }
		public:
            CSLock() {
                m_cs = PTHREAD_MUTEX_INITIALIZER;
                pthread_mutexattr_t attr;
                pthread_mutexattr_init(&attr);
                pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
                pthread_mutex_init(&m_cs, &attr);
            }
            explicit CSLock(int spinCount) {
                m_cs = PTHREAD_MUTEX_INITIALIZER;
                pthread_mutexattr_t attr;
                pthread_mutexattr_init(&attr);
                pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
                pthread_mutex_init(&m_cs, &attr);
            }
			~CSLock() { }
			void SetSpinCount(int count) {  }
			void Lock() { pthread_mutex_lock(&m_cs); }
			void Unlock() { pthread_mutex_unlock(&m_cs); }
		};

#ifdef CCORE_MAC
        class S_CORE_EXPORT Spinlock {
        private:
            void* ul;
        public:
            Spinlock();
            ~Spinlock();
            void Lock();
            void Unlock();
        };
#else
        class S_CORE_EXPORT Spinlock {
        private:
            pthread_spinlock_t sl;
        public:
            Spinlock() { pthread_spin_init(&sl, PTHREAD_PROCESS_PRIVATE); }
            ~Spinlock() { pthread_spin_destroy(&sl); }
            void Lock()
            {
                pthread_spin_lock(&sl);
            }
            void Unlock()
            {
                pthread_spin_unlock(&sl);
            }
        };
#endif

		template<class LOCK>
		class ScopedLock {
			LOCK& m_lock;
		private:
			ScopedLock(const ScopedLock& sl) {}
			ScopedLock& operator=(const ScopedLock& sl) { return *this; }
		public:
			ScopedLock(LOCK& lock) :m_lock(lock) { m_lock.Lock(); }
			~ScopedLock() { m_lock.Unlock(); }
		};

		class Mutex {
		public:
			Mutex() {}
			Mutex(const wchar_t* name) {}
			~Mutex() {}

			void Lock() { m_mutex.lock(); }
			bool TryLock() { return m_mutex.try_lock(); }
			void Unlock() { m_mutex.unlock(); }
		private:
			std::recursive_mutex	m_mutex;
		};

		template<class MUTEX>
		class ScopedMutex {
			MUTEX& m_mutex;
		public:
			ScopedMutex(MUTEX& lock) :m_mutex(lock) { m_mutex.Lock(); }
			~ScopedMutex() { m_mutex.Unlock(); }
		};

        class MutexGuard {
            pthread_mutex_t m_m;
        public:
            MutexGuard(pthread_mutex_t& m) : m_m(m) { pthread_mutex_lock(&m_m); }
            ~MutexGuard() { pthread_mutex_unlock(&m_m); }
        };

        class S_CORE_EXPORT Event {
            pthread_mutex_t m_mutex;
            pthread_cond_t  m_cond;
            bool m_bValid = false;
        public:
            Event()
            {      
                pthread_mutexattr_t attr;
                if (pthread_mutexattr_init(&attr) != 0){
                    m_bValid = false;
                }
                else {
                    m_bValid = true;
                }
                pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
                pthread_mutex_init(&m_mutex, &attr);
                pthread_cond_init(&m_cond, NULL);
            }
            ~Event()
            {
                pthread_mutex_destroy(&m_mutex);
                pthread_cond_destroy(&m_cond);
            }

            bool IsValid() { return m_bValid; }
            void Signal() { MutexGuard g(m_mutex); pthread_cond_signal(&m_cond); }
            void Reset() { MutexGuard g(m_mutex); pthread_cond_destroy(&m_cond); pthread_cond_init(&m_cond, NULL);}
            int Wait(int timeout) {
                timespec Waittime;
                struct timeval now;
                gettimeofday(&now, NULL);
                int nsec = (timeout % 1000) * 1000000;
                Waittime.tv_nsec = nsec % 1000000000;
                Waittime.tv_sec  = now.tv_sec+timeout/1000;
                MutexGuard g(m_mutex);
                return pthread_cond_timedwait(&m_cond, &m_mutex, &Waittime);
            }
        };
	}//namespace base;
}//namespace qb;
#endif

#define SCOPED_LOCK(LOCK) qb::base::ScopedLock<qb::base::CSLock> _scopedl(LOCK);
#define SCOPED_MUTEX(MUTEX) qb::base::ScopedMutex<qb::base::Mutex> _scopedm(MUTEX);

